/*
 *  File Information
 *
 *  Last Modified On: $Date: 2007-06-04 18:04:41 +0200 (Mon, 04 Jun 2007) $
 *  Last Modified By: $Author: mihai.balan $
 */

package ro.pub.cs.stadium.output.xml;

import java.io.OutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import ro.pub.cs.stadium.document.IDocument;
import ro.pub.cs.stadium.document.IState;
import ro.pub.cs.stadium.document.ITransition;
import ro.pub.cs.stadium.document.logic.State;
import ro.pub.cs.stadium.document.logic.Transition;
import ro.pub.cs.stadium.plugin.IOutputPlugin;
import ro.pub.cs.stadium.plugin.PluginInfo;
import ro.pub.cs.stadium.plugin.PluginSettings;
import ro.pub.cs.stadium.plugin.PluginType;

public class XMLOutputPlugin  implements IOutputPlugin {
	private final String docFormat = "XML";
	
	private DocumentBuilderFactory documentFactory;
	private DocumentBuilder documentBuilder;
	private Document outputDocument;
	private Element rootElement;
	
	private String docType = "StadiumFile-0.1";
	private String author = "StadiumApplication-0.1a";
	
	public void writeDocument(IDocument document, OutputStream stream) {
		Node crtAttrib, crtNode, subNode, crtElement, elementAttr;
		State state;
		Transition transition;
		
		docType = document.getDocumentType();
		
		outputDocument = documentBuilder.newDocument();
		/* Create root element <stadium> */
		rootElement = outputDocument.createElement("stadium");
		outputDocument.appendChild(rootElement);
		rootElement.setAttribute("doctype", docType);
		
		/* Create <head> element*/
		crtNode = outputDocument.createElement("head");
		subNode = outputDocument.createElement("author");
		subNode.setTextContent(author);
		crtNode.appendChild(subNode);
		rootElement.appendChild(crtNode);
		
		/*Create <diagram> element*/
		crtNode = outputDocument.createElement("diagram");
		subNode = outputDocument.createElement("states");
		
		for(IState s: document.getStates().values()) {
			/* Create <state> elements */
			if ((state = (State)s) != null) {
				/* <state> element*/
				crtElement = outputDocument.createElement("state");
				/* <state>'s name attribute */
				((Element)crtElement).setAttribute("name", s.getName());
				
				/* <state>'s attributes*/
				for(String key : state.getAttributes().keySet()) {
					elementAttr = outputDocument.createElement("attribute");
					elementAttr.setTextContent(state.getAttributes().get(key));
					/* <attribute>'s name attribute :D */
					((Element)elementAttr).setAttribute("name", key);
				}

				subNode.appendChild(crtElement);
			}
		}
		crtNode.appendChild(subNode);
		
		/* <transitions> element */
		subNode = outputDocument.createElement("transitions");
		for(ITransition t : document.getTransitions().values()) {
			if ((transition = (Transition)t) != null) {
				/* <transition> element */
				crtElement = outputDocument.createElement("transition");
				/* <transition>'s name */
				((Element)crtElement).setAttribute("name", transition.getName());
				
				/* <transition>'s start*/
				((Element)crtElement).setAttribute("start", transition.getStartPoint().getName());

				/* <transition>'s end */
				((Element)crtElement).setAttribute("end", transition.getStartPoint().getName());
				
				/* <transition>'s attributes */
				for(String key : transition.getAttributes().keySet()) {
					elementAttr = outputDocument.createElement("attribute");
					elementAttr.setTextContent(transition.getAttributes().get(key));
					((Element)crtElement).setAttribute("name", key);
				}
								
				subNode.appendChild(crtElement);
			}
		}
		crtNode.appendChild(subNode);
		
		rootElement.appendChild(crtNode);
		writeXMLDocument(outputDocument, stream);
	}

	private void writeXMLDocument(Document outDocument, OutputStream stream) {
		TransformerFactory tf = TransformerFactory.newInstance();
		try {
			Transformer t = tf.newTransformer();
			t.transform(new DOMSource(outDocument), new StreamResult(stream));
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

	public PluginType[] getPluginImplementations() {
		return new PluginType[]{PluginType.OUTPUT};
	}

	public void initialise(PluginSettings settings) {
		try {
			documentFactory = documentFactory.newInstance();
			documentBuilder = documentFactory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

	public Object getPlugin(PluginType type) {
		if (type == PluginType.OUTPUT)
			return this;
		else
			return null;
	}

	public PluginInfo getPluginInfo() {
		return new PluginInfo("XML output plugin v0.1a", null);
	}

	/* (non-Javadoc)
	 * @see ro.pub.cs.stadium.plugin.IOutputPlugin#getDocumentFormat()
	 */
	public String getDocumentFormat() {
		return docFormat;
	}
	
	
}
